/*
  1. Promise 就是一个类 在执行这个类的时候 需要传递一个执行器进去 执行器会立即执行
  2. Promise 中有三种状态 分别为 成功 success 失败 FAIL 等待 pending
    pending -> fulfilled
    pending -> FAIL
    一旦状态确定就不可更改
  3. resolve和reject函数是用来更改状态的
    resolve: fulfilled
    reject: FAIL
  4. then方法内部做的事情就判断状态 如果状态是成功 调用成功的回调函数 如果状态是失败 调用失败回调函数 then方法是被定义在原型对象中的
  5. then成功回调有一个参数 表示成功之后的值 then失败回调有一个参数 表示失败后的原因
  6. 同一个promise对象下面的then方法是可以被调用多次的
  7. then方法是可以被链式调用的, 后面then方法的回调函数拿到值的是上一个then方法的回调函数的返回值
*/

const SUCCESS = 'success'; // 成功状态
const FAIL = 'fail'; // 失败状态
const PENGDING = 'pengding' // 阻塞等待状态

class MyPromise {

    constructor(excutor) {
        // 捕获异常并进行处理
        try {
            excutor(this.resolve, this.reject)
        } catch (e) {
            this.reject(e)
        }
    }

    // promise 状态
    status = PENGDING

    // promise 成功后保存的值
    value = undefined

    // promise 失败的原因
    reason = undefined

    // 成功回调 then链式调用 使用array保存
    successCallBack = [];

    // 失败回调  then链式调用 使用array保存
    failCallBack = [];


    // 成功回调 pending阻塞状态 => success 成功状态
    resolve = value => {
        if (this.status !== PENGDING) return;
        // pengding阻塞状态 => success 成功状态
        this.status = SUCCESS

        this.value = value

        // 异步的情况  判断成功回调是否存在 如果存在 调用
        // then 链式调用 使用while循环
        while (this.successCallBack.length) this.successCallBack.shift()()
    }

    // 失败回调 pending阻塞状态 => FAIL 失败状态
    reject = reason => {
        if (this.status !== PENGDING) return;
        // pending阻塞状态 => FAIL 失败状态
        this.status = FAIL

        this.reason = reason
        // 异步的情况  判断成功回调是否存在 如果存在 调用
        // then 链式调用 使用while循环
        while (this.successCallBack.length) this.successCallBack.shift()()
    }

    then = (successCallBack, failCallBack) => {
        // 参数可选
        successCallBack = successCallBack ? successCallBack : value => value;

        // 参数可选
        failCallBack = failCallBack ? failCallBack : reason => {
            throw reason
        };

        // 返回MyPromise对象
        const newPromise = new MyPromise((resolve, reject) => {
            // 异步处理
            if (this.status === SUCCESS) {
                // 时间设置为0只为将其处理成异步
                setTimeout(() => {
                    try {
                        let x = successCallBack(this.value);
                        resolvePromise(newPromise, x, resolve, reject)
                    } catch (e) {
                        reject(e);
                    }
                }, 0)
            } else if (this.status === FAIL) {
                setTimeout(() => {
                    try {
                        let x = failCallBack(this.reason);
                        resolvePromise(newPromise, x, resolve, reject)
                    } catch (e) {
                        reject(e);
                    }
                }, 0)
            } else {
                // 等待
                // 将成功回调和失败回调存储起来 then 链式调用
                this.successCallBack.push(() => {
                    setTimeout(() => {
                        try {
                            let x = successCallBack(this.value);
                            resolvePromise(promsie2, x, resolve, reject)
                        } catch (e) {
                            reject(e);
                        }
                    }, 0)
                });
                this.failCallBack.push(() => {
                    setTimeout(() => {
                        try {
                            let x = failCallBack(this.reason);
                            resolvePromise(promsie2, x, resolve, reject)
                        } catch (e) {
                            reject(e);
                        }
                    }, 0)
                });
            }
        })
        return newPromise
    }

    // 捕获错误 
    catch = (failCallBack) => {
        return this.then(undefined, failCallBack)
    }

    // 无论成功还是失败都是都执行
    finally = (callBack) => {
        return this.then(value => {
            return MyPromise.resolve(callBack()).then(() => value);
        }, reason => {
            return MyPromise.resolve(callBack()).then(() => {
                throw reason
            })
        })
    }

    static resolve = (value) => {
        // 判断是否是MyPromise对象 是直接返回 不是的话 返回一个新的MyPromise对象
        if (value instanceof MyPromise) return value;
        return new MyPromise(resolve => resolve(value));
    }

    static all(array) {
        let result = [];
        let index = 0;
        return new MyPromise((resolve, reject) => {
            function addData(key, value) {
                result[key] = value;
                index++;

                // 为了异步处理，，等待所有任务都完成才能执行resolve
            
                if (index === array.length) {
                    resolve(result);
                }
            }
            for (let i = 0; i < array.length; i++) {
                let current = array[i];
                if (current instanceof MyPromise) {
                    // promise 对象
                    current.then(value => addData(i, value), reason => reject(reason))
                } else {
                    // 普通值
                    addData(i, array[i]);
                }
            }
        })
    }
}

const resolvePromise = (promsie2, x, resolve, reject) => {
    if (promsie2 === x) {
        // 返回值同一个对象的话，抛出错误
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if (x instanceof MyPromise) {
        // promise 对象
        x.then(resolve, reject);
    } else {
        // 普通值
        resolve(x);
    }
}

module.exports = MyPromise;